package ar.edu.utn.frba.tacs.warnes;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import ar.edu.utn.frba.tacs.warnes.cotizacion.Dolar;
import ar.edu.utn.frba.tacs.warnes.cotizacion.Peso;
import ar.edu.utn.frba.tacs.warnes.dao.AutoDao;
import ar.edu.utn.frba.tacs.warnes.dao.BaseDaoImpl;
import ar.edu.utn.frba.tacs.warnes.dao.PedidoDao;
import ar.edu.utn.frba.tacs.warnes.dao.PiezaDao;
import ar.edu.utn.frba.tacs.warnes.dao.ReservaDao;
import ar.edu.utn.frba.tacs.warnes.dao.VentaDao;
import ar.edu.utn.frba.tacs.warnes.entities.Auto;
import ar.edu.utn.frba.tacs.warnes.entities.Pedido;
import ar.edu.utn.frba.tacs.warnes.entities.Pieza;
import ar.edu.utn.frba.tacs.warnes.entities.Reserva;
import ar.edu.utn.frba.tacs.warnes.entities.Venta;
import ar.edu.utn.frba.tacs.warnes.pieza.PiezaReservadaState;
import ar.edu.utn.frba.tacs.warnes.utils.ConstantesWarnes;
import ar.edu.utn.frba.tacs.warnes.utils.ContenedorWarnes;
import ar.edu.utn.frba.tacs.warnes.utils.SessionWarnes;

public class DBTestCase {

	@Autowired
	private PiezaDao piezaDao;
	private Pieza pieza1;
	private Pieza pieza2;

	@Before
	public void inicializaciones() {
		this.pieza1 = ContenedorWarnes.getInstance().creaUnaPieza("Radio");
		this.pieza2 = ContenedorWarnes.getInstance().creaUnaPieza("Parlante");
		this.piezaDao = PiezaDao.getInstance();
	}

	@After
	public void limpiarContenedor() {
		ContenedorWarnes.getInstance().limpiate();
		// Cerramos la session
		SessionWarnes.cerrarSession();
		SessionWarnes.matate();
	}

	/**
	 * Muestra el modo de uso del DAO
	 */
	@Test
	public void testPiezasDao() {
		// Instanciamos un nuevo DAO
		BaseDaoImpl<Pieza> dao = PiezaDao.getInstance();
		// Creamos una nueva Entity
		Pieza pieza = ContenedorWarnes.getInstance()
				.creaUnaPieza("piezita uno");
		// Grabamos la Entity en la BD, este metodo abre la conexion si esta
		// cerrada.
		pieza.save();
		// Con el DAO hacemos una consulta a la BD que devuelve un listado
		List<Pieza> lista = dao.list();
		// Con el DAO hacemos un count(*) en la BD
		int cantidad = dao.count();
		// Test
		assertEquals(cantidad, lista.size());
		// Borramos la Entity de la BD
		pieza.delete();
		// Con el DAO hacemos un count(*) en la BD
		cantidad = dao.count();
		// Test
		assertEquals(cantidad + 1, lista.size());
	}

	@Test
	public void testPiezasBaseDeDatosSimple() {
		// creo una nueva pieza y la grabo en la bd
		this.pieza1.save();

		// La cantidad de registros
		assertEquals(1, this.piezaDao.list().size());
		// El registro de la 1er pieza
		Pieza miPiezitaUno = this.piezaDao.uniqueResult(this.pieza1.getId());
		assertTrue(this.pieza1.getDescripcion().equals(
				miPiezitaUno.getDescripcion()));

		// creo una nueva pieza y la grabo en la bd
		this.pieza2.save();

		// La cantidad de registros
		assertEquals(2, this.piezaDao.list().size());
		// El registro de la 2da pieza
		Pieza miPiezitaDos = this.piezaDao.uniqueResult(this.pieza2.getId());
		assertTrue(this.pieza2.getDescripcion().equals(
				miPiezitaDos.getDescripcion()));
	}

	@Test
	public void testAutosBaseDeDatosSimple() {
		BaseDaoImpl<Auto> dao = AutoDao.getInstance();

		Auto auto = ContenedorWarnes.getInstance().creaUnAuto("asd-123");
		auto.save();

		assertEquals(1, dao.count());
		Auto miCarro = dao.uniqueResult(auto.getId());
		assertEquals(auto.getPatente(), miCarro.getPatente());

		Auto auto2 = ContenedorWarnes.getInstance().creaUnAuto("dsa-321");
		auto2.save();

		assertEquals(2, dao.count());
		miCarro = dao.uniqueResult(auto2.getId());
		assertEquals(auto2.getPatente(), miCarro.getPatente());
	}

	@Test
	public void testVentasBaseDeDatosSimple() {
		BaseDaoImpl<Venta> ventaDao = VentaDao.getInstance();

		Venta venta = new Venta();
		this.pieza1.cambiarEstado(PiezaReservadaState.getInstance());
		this.pieza2.cambiarEstado(PiezaReservadaState.getInstance());
		venta.venderPieza(this.pieza1);
		venta.venderPieza(this.pieza2);

		// Guardo las piezas
		this.pieza1.save();
		this.pieza2.save();
		// venta.save(); //NO HACE FALTA GRABAR LA VENTA XQ LA PRIMER PIEZA LA
		// GRABA

		assertEquals(1, ventaDao.count());

		List<Pieza> piezas = this.piezaDao.list();
		assertEquals(this.pieza1.getId(), piezas.get(0).getId());
		assertEquals(this.pieza2.getId(), piezas.get(1).getId());

		Venta miVenta = ventaDao.uniqueResult(venta.getId());
		assertEquals(this.pieza1.getId(), miVenta.getPiezasVendidas().get(0)
				.getId());
		assertEquals(this.pieza2.getId(), miVenta.getPiezasVendidas().get(1)
				.getId());
	}

	@Test
	public void testReservaBaseDeDatosSimple() {
		BaseDaoImpl<Reserva> reservaDao = ReservaDao.getInstance();

		Reserva reserva = ContenedorWarnes.getInstance().nuevaReserva();
		reserva.reservarPieza(this.pieza1);
		reserva.reservarPieza(this.pieza2);

		this.pieza1.save();
		this.pieza2.save();
		// reserva.save(); //NO HACE FALTA GRABAR LA RESERVA XQ LA PRIMER PIEZA
		// LA GRABA

		assertEquals(1, reservaDao.count());

		List<Pieza> piezas = this.piezaDao.list();
		assertEquals(reserva.getId(), piezas.get(0).getReserva().getId());
		assertEquals(reserva.getId(), piezas.get(1).getReserva().getId());

		List<Pieza> piezasDeLaReserva = reservaDao
				.uniqueResult(reserva.getId()).getPiezasReservadas();
		assertEquals(this.pieza1.getId(), piezasDeLaReserva.get(0).getId());
		assertEquals(this.pieza2.getId(), piezasDeLaReserva.get(1).getId());
	}

	@Test
	public void testComplejo() {
		Auto auto1 = ContenedorWarnes.getInstance().creaUnAuto("asd-123");
		this.pieza1.setAutoOrigen(auto1);
		this.pieza1.setCategoria(ConstantesWarnes.Categoria.PARTES);
		Auto auto2 = ContenedorWarnes.getInstance().creaUnAuto("dsa-321");
		this.pieza2.setAutoOrigen(auto2);
		this.pieza2.setCategoria(ConstantesWarnes.Categoria.USADOS);

		// Grabo las piezas (y el auto)
		this.pieza1.save();
		this.pieza2.save();
		List<Pieza> piezas = this.piezaDao.list();

		// Test de los autos de cada pieza (BD)
		assertEquals(auto1.getPatente(), piezas.get(0).getAutoOrigen()
				.getPatente());
		assertEquals(auto2.getPatente(), piezas.get(1).getAutoOrigen()
				.getPatente());
		// Test de la categoria de cada pieza (BD)
		assertEquals(ConstantesWarnes.Categoria.PARTES, piezas.get(0)
				.getCategoria());
		assertEquals(ConstantesWarnes.Categoria.USADOS, piezas.get(1)
				.getCategoria());
		// Test del estado de cada pieza
		assertTrue(this.pieza1.estaDisponible());
		assertTrue(this.pieza2.estaDisponible());

		Pedido pedido = ContenedorWarnes.getInstance().crearUnPedido(piezas);
		// Test del estado de cada pieza
		assertTrue(this.pieza1.estaReservada());
		assertTrue(this.pieza2.estaReservada());
		// Grabo la pieza
		pedido.save();

		Pedido pedidoBD = PedidoDao.getInstance().uniqueResult(pedido.getId());
		// Test de las piezas del pedido (BD)
		assertEquals(pedido.getPiezas().size(), pedidoBD.getPiezas().size());
		// Test del estado del pedido (BD)
		assertTrue(pedidoBD.estaEnCurso());
		assertFalse(pedidoBD.estaCancelado());
		assertFalse(pedidoBD.estaEfectivizado());
		// Test del estado de cada pieza (BD)
		for (Pieza pieza : pedidoBD.getPiezas()) {
			assertTrue(pieza.estaReservada());
			assertFalse(pieza.estaVendida());
		}

		// Test agrego una nueva pieza al pedido (BD)
		Pieza pieza3 = ContenedorWarnes.getInstance().creaUnaPieza("Parlante");
		assertEquals(2, pedidoBD.getCantidadPiezas().intValue());
		pedido.agregarPieza(pieza3);
		pedido.save();
		pedidoBD = PedidoDao.getInstance().uniqueResult(pedido.getId());
		assertEquals(3, pedidoBD.getCantidadPiezas().intValue());

		pedido.efectivizar();
		// Test del estado de cada pieza
		assertTrue(this.pieza1.estaVendida());
		assertTrue(this.pieza2.estaVendida());

		pedido.save();
		pedidoBD = PedidoDao.getInstance().uniqueResult(pedido.getId());
		assertEquals(pedido.getPiezas().size(), pedidoBD.getPiezas().size());
		// Test del estado del pedido (BD)
		assertFalse(pedidoBD.estaEnCurso());
		assertFalse(pedidoBD.estaCancelado());
		assertTrue(pedidoBD.estaEfectivizado());
		// Test del estado de cada pieza (BD)
		for (Pieza pieza : pedidoBD.getPiezas()) {
			assertTrue(pieza.estaVendida());
			assertFalse(pieza.estaDisponible());
		}

		// Test cambio dinamico de moneda (DB)
		Float precioEnPesos = new Float(5);
		Float precioMultiplicado = precioEnPesos * ContenedorWarnes.getInstance().getValorMoneda();
		ContenedorWarnes.getInstance().setMoneda(Peso.getInstance());
		ContenedorWarnes.getInstance().cambiarCotizacion(Peso.getInstance(), new Float(1));
		this.pieza1.setPrecioEnPesos(precioEnPesos);
		this.pieza1.save();

		Pieza pieza1DB = this.piezaDao.uniqueResult(this.pieza1.getId());
		assertEquals(precioEnPesos, pieza1DB.getPrecioSegunMoneda());

		ContenedorWarnes.getInstance().setMoneda(Dolar.getInstance());
		this.pieza1.save();
		precioMultiplicado = precioEnPesos / ContenedorWarnes.getInstance().getValorMoneda();
		assertEquals(precioMultiplicado, pieza1DB.getPrecioSegunMoneda());

	}
}
